<!doctype HTML public "-//W3C//DTD HTML 4.0 Frameset//EN">
<html>
<title>Bloomberg Development Environment</title>
<html>
<pre>
// Copyright 2016-2023 Bloomberg Finance L.P.
// SPDX-License-Identifier: Apache-2.0
//
// Licensed under the Apache License, Version 2.0 (the &quot;License&quot;);
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an &quot;AS IS&quot; BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// bmqa_messageproperties.h                                           -*-C++-*-
#ifndef INCLUDED_BMQA_MESSAGEPROPERTIES
#define INCLUDED_BMQA_MESSAGEPROPERTIES

//@PURPOSE: Provide a VST representing message properties.
//
//@CLASSES:
//  bmqa::MessageProperties:         VST representing message properties.
//  bmqa::MessagePropertiesIterator: Mechanism to iterate over properties.
//
//@SEE ALSO: bmqt::PropertyType
//
//@DESCRIPTION: &#39;bmqa::MessageProperties&#39; provides a VST representing message
// properties.  Message properties are a collection of name-value pairs that
// producer can associate with a message, and consumer can retrieve from the
// corresponding message.  In order to keep their usage flexible, no schema is
// enforced for the message properties, and their format (names and data types)
// should be negotiated by producers and consumers.  Message properties can be
// used for routing, pipelining or filtering messages within the application.
// It can be efficient to specify such message attributes in the properties
// instead of the message payload, because application does not have to decode
// entire payload to retrieve these attributes.
// &#39;bmqa::MessagePropertiesIterator&#39; provides a mechanism to iterate over all
// the properties of a &#39;bmqa::MessageProperties&#39; object.
//
///Restrictions on Property Names
///------------------------------
//
//: o Length of a property name must be greater than zero and must *not* exceed
//:   &#39;bmqa::MessageProperties::k_MAX_PROPERTY_NAME_LENGTH&#39;
//
//: o First character of the property name must be alpha-numeric.
//
///Restrictions on Property Values
///-------------------------------
//
//: o Length of a property value must be non-negative (ie, can be zero) and
//:   must *not* exceed &#39;bmqa::MessageProperties::k_MAX_PROPERTY_VALUE_LENGTH&#39;.
//:   Note that this restriction is obviously applicable to property values
//:   with types &#39;bmqt::PropertyType::e_STRING&#39; and
//:   &#39;bmqt::PropertyType::e_BINARY&#39;, because for all other property value
//:   types, size is implicitly applicable based on the type (see &#39;Data Types
//:   and Size&#39; section in &#39;bmqt::PropertyType&#39; component).
//


// BMQ
#include &lt;bmqscm_version.h&gt;
#include &lt;bmqt_resultcode.h&gt;
#include &lt;bmqt_propertytype.h&gt;

// BDE
#include &lt;bdlbb_blob.h&gt;
#include &lt;bsl_string.h&gt;
#include &lt;bslma_allocator.h&gt;
#include &lt;bslma_usesbslmaallocator.h&gt;
#include &lt;bslmf_nestedtraitdeclaration.h&gt;
#include &lt;bsls_alignedbuffer.h&gt;
#include &lt;bsls_types.h&gt;
#include &lt;bsl_cstdint.h&gt;


namespace BloombergLP {

// FORWARD DECLARATION
namespace bmqp { class MessageProperties; }
namespace bmqp { class MessagePropertiesIterator; }

namespace bmqa {

                          // =======================
                          // class MessageProperties
                          // =======================

class MessageProperties {
    // Provide a VST representing message properties.

    // FRIENDS
    friend class MessagePropertiesIterator;

  private:
    // PRIVATE CONSTANTS
    static const int k_MAX_SIZEOF_BMQP_MESSAGEPROPERTIES = 176;
        // Constant representing the maximum size of a
        // &#39;bmqp::MessageProperties&#39; object, so that the below AlignedBuffer
        // is big enough.

    // PRIVATE TYPES
    typedef
    bsls::AlignedBuffer&lt;k_MAX_SIZEOF_BMQP_MESSAGEPROPERTIES&gt; ImplBuffer;

  private:
    // DATA
    mutable bmqp::MessageProperties *d_impl_p;
                                        // Pointer to the implementation object
                                        // in &#39;d_buffer&#39;, providing a shortcut
                                        // type safe cast to that object.  This
                                        // variable *must* *be* the first
                                        // member of this class, as other
                                        // components in bmqa package may
                                        // reinterpret_cast to that variable.

    ImplBuffer                       d_buffer;
                                        // Buffer containing the implementation
                                        // object, maximally aligned.

    bslma::Allocator                *d_allocator_p;

  public:
    // PUBLIC CONSTANTS
    static const int k_MAX_NUM_PROPERTIES        = 255;
        // Maximum number of properties that can appear in a &#39;bmqa::Message&#39;.

    static const int k_MAX_PROPERTIES_AREA_LENGTH = (64 * 1024 * 1024) - 8;
       // Maximum length of all the properties (including their names, values
       // and the wire protocol overhead).  Note that this value is just under
       // 64 MB.

    static const int k_MAX_PROPERTY_NAME_LENGTH  = 4095;
        // Maximum length of a property name.

    static const int k_MAX_PROPERTY_VALUE_LENGTH = 67104745;  // ~64 MB
       // Maximum length of a property value.  Note that this value is just
       // under 64 MB.  Also note that this value is calculated assuming that
       // there is only one property and property&#39;s name has maximum allowable
       // length, and also takes into consideration the protocol overhead.

  public:
    // TRAITS
    BSLMF_NESTED_TRAIT_DECLARATION(MessageProperties,
                                   bslma::UsesBslmaAllocator)

    // CREATORS
    explicit
    MessageProperties(bslma::Allocator *basicAllocator = 0);
        // Create an empty instance of &#39;MessageProperties&#39;.  Optionally
        // specify a &#39;basicAllocator&#39; used to supply memory.  Note that it is
        // more efficient to use a &#39;MessageProperties&#39; object retrieved via
        // &#39;Session::loadMessageProperties&#39;, instead of creating it via this
        // constructor.

    MessageProperties(const MessageProperties&amp;  other,
                      bslma::Allocator         *basicAllocator = 0);
        // Create an instance of &#39;MessageProperties&#39; having the same value as
        // the specified &#39;other&#39;, that will use the optionally specified
        // &#39;basicAllocator&#39; to supply memory.

    ~MessageProperties();
        // Destroy this object.

    // MANIPULATORS
    MessageProperties&amp; operator=(const MessageProperties&amp; rhs);
        // Assign to this object the value of the specified &#39;rhs&#39; object.

    bool remove(const bsl::string&amp;        name,
                bmqt::PropertyType::Enum *buffer = 0);
        // Remove the property with the specified &#39;name&#39; if one exists and
        // return true and load into the optionally specified &#39;buffer&#39; the data
        // type of the property.  Return false if the &#39;name&#39; property does not
        // exist, and leave the &#39;buffer&#39; unchanged.

    void clear();
        // Remove all properties from this instance.  Note that &#39;numProperties&#39;
        // will return zero after invoking this method.

    int setPropertyAsBool(const bsl::string&amp; name, bool value);
    int setPropertyAsChar(const bsl::string&amp; name, char value);
    int setPropertyAsShort(const bsl::string&amp; name, short value);
    int setPropertyAsInt32(const bsl::string&amp; name, bsl::int32_t value);
    int setPropertyAsInt64(const bsl::string&amp; name, bsls::Types::Int64 value);
    int setPropertyAsString(const bsl::string&amp; name, const bsl::string&amp; value);
    int setPropertyAsBinary(const bsl::string&amp;       name,
                            const bsl::vector&lt;char&gt;&amp; value);
        // Set a property with the specified &#39;name&#39; having the specified
        // &#39;value&#39; with the corresponding data type.  Return zero on success,
        // and a non-zero value in case of failure.  Note that if a property
        // with &#39;name&#39; and the same type exists, it will be updated with the
        // provided &#39;value&#39;, however if the data type of the existing property
        // differs, an error will be returned.

    int streamIn(const bdlbb::Blob&amp; blob);
        // Populate this instance with its BlazingMQ wire protocol
        // representation from the specified &#39;blob&#39;.  Return zero on success,
        // and a non-zero value otherwise.

    // ACCESSORS
    int numProperties() const;
        // Return the total number of properties set in this instance.

    int totalSize() const;
        // Return the total size (in bytes) of the wire representation of this
        // instance.  Note that returned value includes the BlazingMQ wire
        // protocol overhead as well.

    bool hasProperty(const bsl::string&amp;        name,
                     bmqt::PropertyType::Enum *type = 0) const;
        // Return true if a property with the specified &#39;name&#39; exists and load
        // into the optionally specified &#39;type&#39; the type of the property.
        // Return false otherwise.

    bmqt::PropertyType::Enum propertyType(const bsl::string&amp; name) const;
        // Return the type of property having the specified &#39;name&#39;.  Behavior
        // is undefined unless &#39;hasProperty&#39; returns true for the property
        // &#39;name&#39;.

    bool getPropertyAsBool(const bsl::string&amp; name) const;
    char getPropertyAsChar(const bsl::string&amp; name) const;
    short getPropertyAsShort(const bsl::string&amp; name) const;
    bsl::int32_t getPropertyAsInt32(const bsl::string&amp; name) const;
    bsls::Types::Int64 getPropertyAsInt64(const bsl::string&amp; name) const;
    const bsl::string&amp; getPropertyAsString(const bsl::string&amp; name) const;
    const bsl::vector&lt;char&gt;&amp; getPropertyAsBinary(
                                                const bsl::string&amp; name) const;
        // Return the property having the corresponding type and the specified
        // &#39;name&#39;.  Behavior is undefined unless property with &#39;name&#39; exists.

    bool getPropertyAsBoolOr(const bsl::string&amp; name, bool value) const;
    char getPropertyAsCharOr(const bsl::string&amp; name, char value) const;
    short getPropertyAsShortOr(const bsl::string&amp; name, short value) const;
    bsl::int32_t getPropertyAsInt32Or(const bsl::string&amp; name,
                                      bsl::int32_t       value) const;
    bsls::Types::Int64 getPropertyAsInt64Or(const bsl::string&amp; name,
                                            bsls::Types::Int64 value) const;
    const bsl::string&amp; getPropertyAsStringOr(const bsl::string&amp; name,
                                             const bsl::string&amp; value) const;
    const bsl::vector&lt;char&gt;&amp; getPropertyAsBinaryOr(
                                         const bsl::string&amp;       name,
                                         const bsl::vector&lt;char&gt;&amp; value) const;
        // Return the property having the corresponding type and the specified
        // &#39;name&#39; if property with such a name exists.  Return the specified
        // &#39;value&#39; if property with &#39;name&#39; does not exist.

    const bdlbb::Blob&amp;
    streamOut(bdlbb::BlobBufferFactory *bufferFactory) const;
        // Return a blob having the BlazingMQ wire protocol representation of
        // this instance, using the specified &#39;bufferFactory&#39; to build the
        // blob.  Behavior is undefined unless &#39;bufferFactory&#39; is non-null.
        // Note that if this instance is empty (i.e., &#39;numProperties()&#39; == 0),
        // returned blob will be empty.  In other words, an empty instance has
        // no wire representation.

    bsl::ostream&amp; print(bsl::ostream&amp; stream,
                        int           level          = 0,
                        int           spacesPerLevel = 4) const;
        // Format this object to the specified output &#39;stream&#39; at the (absolute
        // value of) the optionally specified indentation &#39;level&#39; and return a
        // reference to &#39;stream&#39;.  If &#39;level&#39; is specified, optionally specify
        // &#39;spacesPerLevel&#39;, the number of spaces per indentation level for
        // this and all of its nested objects.  If &#39;level&#39; is negative,
        // suppress indentation of the first line.  If &#39;spacesPerLevel&#39; is
        // negative format the entire output on one line, suppressing all but
        // the initial indentation (as governed by &#39;level&#39;).  If &#39;stream&#39; is
        // not valid on entry, this operation has no effect.
};

// FREE OPERATORS
bsl::ostream&amp; operator&lt;&lt;(bsl::ostream&amp; stream, const MessageProperties&amp; rhs);
    // Format the specified &#39;rhs&#39; to the specified output &#39;stream&#39; and return a
    // reference to the modifiable &#39;stream&#39;.


                      // ===============================
                      // class MessagePropertiesIterator
                      // ===============================

class MessagePropertiesIterator {
    // Provide a mechanism to iterator over all the properties in an instance
    // of &#39;bmqa::MessageProperties&#39;.  The order of the iteration is
    // implementation defined.  An iterator is *valid* if it is associated with
    // a property , otherwise it is *invalid*.  Behavior is undefined if the
    // underlying instance of &#39;bmqa::MessageProperties&#39; is modified during the
    // lifetime of this iterator.

  private:
    // PRIVATE CONSTANTS
    static const int k_MAX_SIZEOF_BMQP_MESSAGEPROPERTIESITER = 64;
        // Constant representing the maximum size of a
        // &#39;bmqp::MessagePropertiesIterator&#39; object, so that the below
        // AlignedBuffer is big enough.

    // PRIVATE TYPES
    typedef
    bsls::AlignedBuffer&lt;k_MAX_SIZEOF_BMQP_MESSAGEPROPERTIESITER&gt; ImplBuffer;

  private:
    // DATA
    mutable bmqp::MessagePropertiesIterator *d_impl_p;
                                        // Pointer to the implementation object
                                        // in &#39;d_buffer&#39;.  This variable *must*
                                        // *be* the first member of this class.
                                        // If the value is null, the object
                                        // has not been constructed in the
                                        // &#39;d_buffer&#39;.

    ImplBuffer                               d_buffer;
                                        // Buffer containing the implementation
                                        // object

  public:
    // CREATORS
    MessagePropertiesIterator();
        // Create an empty iterator instance.  The only valid operations that
        // can be invoked on an empty instance are copying, assignment and
        // destruction.

    explicit
    MessagePropertiesIterator(const MessageProperties *properties);
        // Create an iterator for the specified &#39;properties&#39;.  Behavior is
        // undefined unless &#39;properties&#39; is not null.

    MessagePropertiesIterator(const MessagePropertiesIterator&amp; other);
        // Copy constructor from the specified &#39;other&#39;.

    ~MessagePropertiesIterator();
        // Destroy this iterator.

    // MANIPULATORS
    MessagePropertiesIterator&amp;
    operator=(const MessagePropertiesIterator&amp; rhs);
        // Assignment operator from the specified &#39;rhs&#39;.

    bool hasNext();
        // Advance this iterator to refer to the next property of the
        // associated &#39;MessageProperties&#39; instance, if there is one and return
        // true, return false otherwise.  Behavior is undefined unless this
        // method is being invoked for the first time on this object or
        // previous call to &#39;hasNext&#39; returned true.  Note that the order of
        // the iteration is not specified.

    // ACCESSORS
    const bsl::string&amp; name() const;
        // Return a reference offering non-modifiable access to the name of the
        // property being pointed by the iterator.  Behavior is undefined
        // unless last call to &#39;hasNext&#39; returned true.

    bmqt::PropertyType::Enum type() const;
        // Return the data type of property being pointed by the iterator.
        // Behavior is undefined unless last call to &#39;hasNext&#39; returned true;

    bool getAsBool() const;
    char getAsChar() const;
    short getAsShort() const;
    bsl::int32_t getAsInt32() const;
    bsls::Types::Int64 getAsInt64() const;
    const bsl::string&amp; getAsString() const;
    const bsl::vector&lt;char&gt;&amp; getAsBinary() const;
        // Return property value having the corresponding type being currently
        // being pointed by this iterator instance.  Behavior is undefined
        // unless last call to &#39;hasNext&#39; returned true.  Behavior is also
        // undefined unless property&#39;s data type matches the requested type.
};

}  // close package namespace


// ============================================================================
//                             INLINE DEFINITIONS
// ============================================================================


                          // -----------------------
                          // class MessageProperties
                          // -----------------------

inline
bsl::ostream&amp;
bmqa::operator&lt;&lt;(bsl::ostream&amp;                  stream,
                 const bmqa::MessageProperties&amp; rhs)
{
    return rhs.print(stream, 0, -1);
}

}  // close enterprise namespace

#endif
</pre>
</body>
</html>
